/*******************************************************************************
 * Copyright (c) 2010, 2015 git@git.oschina.net:kaiwill/springstage.git
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 *******************************************************************************/
package com.qinyeit.serviceapp.service.system.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.qinyeit.serviceapp.entity.Employee;
import com.qinyeit.serviceapp.entity.system.ManagementAccount;
import com.qinyeit.serviceapp.entity.system.ManagementPermission;
import com.qinyeit.serviceapp.entity.system.ManagementRole;
import com.qinyeit.serviceapp.exception.BusinessRunTimeException;
import com.qinyeit.serviceapp.repository.system.ManagementAccountRepository;
import com.qinyeit.serviceapp.repository.system.ManagementPermissionRepository;
import com.qinyeit.serviceapp.repository.system.ManagementRoleRepository;
import com.qinyeit.serviceapp.service.organization.EmployeeService;
import com.qinyeit.serviceapp.service.system.ManagementAccountService;
import com.qinyeit.serviceapp.service.system.ManagementPermissionService;
import com.qinyeit.serviceapp.service.system.ManagementRoleService;
import com.qinyetech.springstage.core.entity.Status;
import com.qinyetech.springstage.core.entity.search.SearchOperator;
import com.qinyetech.springstage.core.entity.search.Searchable;
import com.qinyetech.springstage.core.lang.QyMap;
import com.qinyetech.springstage.core.repository.jdbc.PageNamedParameterJdbcTemplate;
import com.qinyetech.springstage.core.service.BaseService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.validation.BindingResult;

import java.util.*;
import java.util.stream.Collectors;

/**
 * ClassName: SystemAccountServiceImpl <br/>
 * Function: 系统账号业务实现 <br/>
 * date: 2015年8月22日 上午10:42:57 <br/>
 *
 * @author wuqing
 * @version
 * @since JDK 1.7
 */
@Slf4j
@Service
public class ManagementAccountServiceImpl extends BaseService<ManagementAccount, Long> implements ManagementAccountService {

//	private static final Log log=LogFactory.getLog(ManagementAccountServiceImpl.class);
	private String algorithmName = "md5";
	private final int hashIterations = 2;
	private final int apiTokenExpired=30; //api token过期时间 单位 天

	@Value("${managementAccount.default-password:123456}")
	private String defaultPassword;

	private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();

	@Autowired
	private ManagementAccountRepository systemaccountRepository;
	@Autowired
	private ManagementRoleRepository systemRoleRepository;
    @Autowired
    private ManagementPermissionRepository systemPermissionRepository;
	@Autowired
	private EmployeeService employeeService;
	@Autowired
	private PageNamedParameterJdbcTemplate jdbcTemplate;
	@Autowired
	private ManagementRoleService managementRoleService;
	@Autowired
	private ManagementPermissionService managementPermissionService;
	/**
	 * 保存账号
	 */
	@Override
	public ManagementAccount save(ManagementAccount account) {
		account.setCreateAt(new Date());
		if(StringUtils.isEmpty(account.getPassword())){
			account.setPassword(defaultPassword);
		}
		encryptPassword(account);
		return super.save(account);
	}


	/**
	 * encryptPassword:加密明文密码 <br/>
	 * @author wuqing
	 * @param account
	 * @since JDK 1.7
	 */
	private void encryptPassword(ManagementAccount account) {
		String salt=randomNumberGenerator.nextBytes().toHex();
		account.setSalt(salt);
		String newPassword = encryptPassword(account.getPassword(),account.getCredentialsSalt());
		account.setPasswordDigist(newPassword);
	}

	/**
	 * encryptPassword:加密明文密码. <br/>
	 * @author wuqing
	 * @param password 明文密码
	 * @param salt 盐值
	 * @return
	 * @since JDK 1.7
	 */
	private String encryptPassword(String password,String salt){
		return new SimpleHash(algorithmName, password,
				ByteSource.Util.bytes(salt),
				hashIterations).toHex();
	}

	@Override
	public ManagementAccount update(ManagementAccount systemAccount){
		if(systemAccount==null || !super.exists(systemAccount.getId())){
			throw new RuntimeException("账号不存在");
		}
		systemAccount=super.update(systemAccount);
		return systemAccount;
	}

	@Override
	public ManagementAccount updatePassword(Long id, String password) {
		ManagementAccount account=super.findById(id);
		if(account==null){
			throw new RuntimeException("账号不存在");
		}
		if(StringUtils.isBlank(password)){
			password = getDefaultPassword();
		}
		account.setPassword(password);
		encryptPassword(account);

		account=super.update(account);
		return account;
	}

	@Override
	public ManagementAccount findByAccount(String account) {
		Assert.hasLength(account,"账号不能为空");
		Searchable searchable = Searchable.newSearchable();
		searchable.addSearchFilter("deleted", SearchOperator.eq, false);
		searchable.addSearchFilter("account", SearchOperator.eq, account);
		ManagementAccount sysAccount=super.findOne(searchable);
		return sysAccount;
	}

	@Override
	public ManagementAccount findByAdminAccount(String account) {
		Assert.hasLength(account,"账号不能为空");
		Searchable searchable = Searchable.newSearchable();
		searchable.addSearchFilter("deleted", SearchOperator.eq, false);
		searchable.addSearchFilter("account", SearchOperator.eq, account);
		searchable.addSearchFilter("admin",SearchOperator.eq,true);
		ManagementAccount sysAccount=super.findOne(searchable);
		return sysAccount;
	}

	@Override
	public ManagementAccount findByAccountWithAdmin(String account,String adminAccount) {
		ManagementAccount admin=findByAdminAccount(adminAccount);
		if(admin==null || admin.getMerchantGroupId()==null){ //商户组不存在
			return null;
		}
		Searchable searchable = Searchable.newSearchable();
		searchable.addSearchFilter("deleted", SearchOperator.eq, false);
		searchable.addSearchFilter("account", SearchOperator.eq, account);
		searchable.addSearchFilter("merchantGroupId", SearchOperator.eq, admin.getMerchantGroupId());
		ManagementAccount sysAccount=super.findOne(searchable);
		return sysAccount;
	}

	@Override
	public String getDefaultPassword() {
		return defaultPassword;
	}

	@Override
	public boolean validatePassword(Long id, String oldPassword) {
		ManagementAccount sysAccount=systemaccountRepository.findById(id).get();
		String oldPasswordEncrypt = new SimpleHash(algorithmName, oldPassword,
				ByteSource.Util.bytes(sysAccount.getCredentialsSalt()),
				hashIterations).toHex();
		if(oldPasswordEncrypt.equals(sysAccount.getPasswordDigist())){
			return true;
		}
		return false;
	}

	/**
	 * 修改账号权限
	 * @param id 账号id
	 * @param roleIds 权限ids
     * @return
     */
	@Override
	public ManagementAccount allotRole(Long id, List<Long> roleIds) {
		ManagementAccount systemAccount=this.findById(id);
		if(CollectionUtils.isEmpty(roleIds)){
			systemAccount.setRoles(new HashSet<ManagementRole>());
		}else{
			List<ManagementRole> roleList=systemRoleRepository.findAllById(roleIds);
			systemAccount.setRoles(new HashSet<ManagementRole>(roleList));
		}
		this.update(systemAccount);
		return systemAccount;
	}

	@Override
    public Set<String> findRoleCodeSet(String account,boolean isAdmin,String adminAccount) {
		ManagementAccount systemAccount = null;
		if(isAdmin){
			systemAccount = this.findByAdminAccount(account);
		}else {
			systemAccount = this.findByAccountWithAdmin(account,adminAccount);
		}

//		ManagementAccount systemAccount=this.findByAccount(account);
		Set<String> strRoles=new HashSet<>();
		if(systemAccount!=null){
			for (ManagementRole role : systemAccount.getRoles()) {
				strRoles.add(role.getCode());
			}
		}
		return strRoles;
    }

	/**
	 * 根据账户获取权限字符串
	 * @param account 当前账号
	 * @return 权限字符串
     */
    @Override
    public Set<String> findPermissionCodeSet(String account) {
		Set<String> strPermission=systemPermissionRepository.findPermission(account);
		return strPermission;
    }

	@Override
	public ManagementAccount authenticate(String account, String password) throws AuthenticationException,LockedAccountException {
		ManagementAccount systemAccount=this.findByAccount(account);
		if(systemAccount==null || StringUtils.isEmpty(password)){
			throw new AuthenticationException();
		}
		if(systemAccount.isLocked()){
			throw new LockedAccountException();
		}
		String encryptPassword=this.encryptPassword(password, systemAccount.getCredentialsSalt());
		if(!encryptPassword.equals(systemAccount.getPasswordDigist())){
			throw new AuthenticationException();
		}
		this.update(systemAccount);
		return systemAccount;
	}


	@Override
	public boolean updateUnlock(ManagementAccount currentAccount, Long id) {
		if(currentAccount==null || id==null || id==0){
			return false;
		}

		ManagementAccount systemAccount = findById(id);
		if(systemAccount==null){
			return false;
		}
		systemAccount.setStatus(Status.NORMAL);
		systemAccount.setLocked(false);
		super.save(systemAccount);

		return true;
	}

	@Override
	public boolean existsRepeat(BindingResult result, Long id, String account) {
		if(StringUtils.isBlank(account)){
			result.rejectValue("account","account.empty","请填写账号");
			return true;
		}
		Searchable searchable = null;
		ManagementAccount systemAccount = null;
		//验证account
		searchable = Searchable.newSearchable()
				.addSearchParam("id_ne", id)
				.addSearchParam("account_eq", account.trim());
		systemAccount = super.findOne(searchable);
		if(systemAccount!=null){
			result.rejectValue("account","account.exists","账号重复");
			return true;
		}
		return false;
	}

	@Override
	public void saveAccount(JSONObject data, Long merchantGroupId) {
		if (data==null){
			throw new BusinessRunTimeException("账号信息为空",10001);
		}
		Long id = data.getLong("id");
		Long employeeId = data.getLong("employeeId");
		if (employeeId==null){
			throw new BusinessRunTimeException("该员工不存在",10003);
		}
		Employee employee = employeeService.findById(employeeId);
		if(employee==null){
			throw new BusinessRunTimeException("该员工不存在",10003);
		}
		String name = data.getString("account");
		String password = data.getString("password");
		String confirmPassword = data.getString("passwordConfirm");
		if(StringUtils.isBlank(name)){
			throw new BusinessRunTimeException("请填写账号",10001);
		}

		ManagementAccount account = null;
		if(id==null){
			//验证账号
			ManagementAccount managementAccount = findByAccount(name);
			if(managementAccount!=null){
				throw new BusinessRunTimeException("该账号已存在",10003);
			}
			if(StringUtils.isBlank(password) || StringUtils.isBlank(confirmPassword)){
				throw new BusinessRunTimeException("请填写密码或确认密码",10001);
			}
			if(!password.equals(confirmPassword)){
				throw new BusinessRunTimeException("两次密码不一致",10002);
			}
			account = new ManagementAccount();
			account.setMerchantGroupId(merchantGroupId);
			account.setAccount(name);
			account.setRealName(employee.getName());
			account.setPassword(password);
			account.setAdmin(false);
			account.setPasswordConfirm(confirmPassword);
			account.setLocked(false);

		}else {
			account = this.findById(id);
//			account.setAccount(name);
			if(StringUtils.isNotBlank(password)){
				if(StringUtils.isBlank(password) || StringUtils.isBlank(confirmPassword)){
					throw new BusinessRunTimeException("请填写密码或确认密码",10001);
				}
				if(!password.equals(confirmPassword)){
					throw new BusinessRunTimeException("两次密码不一致",10002);
				}
				account.setPassword(password);
				encryptPassword(account);
			}
		}
		//保存岗位
		JSONArray gangweis = data.getJSONArray("gangwei");
		Set<ManagementRole> roleSet = new HashSet<>();
		ManagementRole role = null;
		if(CollectionUtils.isNotEmpty(gangweis)){
			for (int i = 0; i < gangweis.size(); i++) {
				role = managementRoleService.findById(gangweis.getLong(i));
				if(role!=null){
					roleSet.add(role);
				}
			}
		}
		account.setRoles(roleSet);
		if(id==null){
			account = this.save(account);
		}else {
			account = this.update(account);
		}
		employee.setAccount(account);
		employeeService.update(employee);
	}

	@Override
	public List<Map<String, Object>> getRolesByAccount(Long accountId, Long merchantGroupId) {
    	String sql = "SELECT ma.id,ma.account,ma.admin,tmp.management_role_id,mr.name from management_accounts ma\n" +
				"LEFT JOIN (\n" +
				"\tSELECT mar.management_account_id,mar.management_role_id from management_account_roles mar where mar.management_account_id = :accountId) tmp \n" +
				"\ton tmp.management_account_id = ma.id\n" +
				"LEFT JOIN management_roles mr on mr.id = tmp.management_role_id\n" +
				"where tmp.management_role_id is not null and ma.merchant_group_id = :merchantGroupId and ma.is_deleted=0 and mr.merchant_group_id = :merchantGroupId";
		QyMap map = QyMap.map("accountId",accountId)
				.setv("merchantGroupId",merchantGroupId);
		List<Map<String,Object>> mapList = jdbcTemplate.queryForList(sql,map);
		return mapList;
	}

	@Override
	public List<Map<String,Object>> getPermissionCodeSet(Long accountId) {
		String sql = "SELECT mp.id AS permission_id,mp.code,mp.name,mp.parent_id FROM management_role_permissions mrp\n" +
				"LEFT JOIN management_permissions mp ON mp.id=mrp.management_permission_id\n" +
				" WHERE mrp.management_role_id IN(\n" +
				"\tSELECT management_role_id FROM management_account_roles WHERE management_account_id = :accountId\n" +
				"\t)";

    	QyMap map = QyMap.map("accountId",accountId);
    	List<Map<String,Object>> mapList = jdbcTemplate.queryForList(sql,map);
    	List<QyMap> permissions = mapList.stream().map(QyMap::WRAP).collect(Collectors.toList());
		List<Long> permissionIds = Lists.newArrayList();
    	if (CollectionUtils.isNotEmpty(permissions)){
			for (QyMap permission : permissions) {
				permissionIds.add(permission.getLong("permission_id"));
				associateList(permission.getLong("parent_id"),permissionIds);
			}
		}
		if(CollectionUtils.isNotEmpty(permissionIds)){
			sql = "SELECT code,name from management_permissions where id in(:ids)";
			map = QyMap.map("ids",permissionIds);
//		log.info("permissionIds --- : {}",permissionIds);
			mapList = jdbcTemplate.queryForList(sql,map);
		}else {
			mapList = Lists.newArrayList();
		}

		return mapList;

	}


	public void updatePicHead(ManagementAccount currentAccount){
    	super.update(currentAccount);
	}


	@Override
	public ManagementAccount updateAccountPassword(String oldPassword, String newPassword, String confirmPassword,Long accountId) {

		if (StringUtils.isBlank(oldPassword)){
			throw new RuntimeException("旧密码不能为空");
		}
		if (StringUtils.isBlank(newPassword)){
			throw new RuntimeException("新密码不能为空");
		}
		if (StringUtils.isBlank(confirmPassword)){
			throw new RuntimeException("确认密码不能为空");
		}
		//验证两次输入密码是否一致
		if (!newPassword.equals(confirmPassword)){
			throw new RuntimeException("两次输入密码不一致");
		}
		Boolean boo = this.validatePassword(accountId,oldPassword);
		if (!boo){
			throw new RuntimeException("原密码输入不正确");
		}
		//修改密码
		ManagementAccount account = this.findById(accountId);
		account.setPassword(newPassword);
		encryptPassword(account);
		account=super.update(account);
		return account;
	}


	/**
	 *
	 * associateList:处理关联 <br>
	 *
	 * @author wuqing
	 * @param parentId 父级id
	 * @param pids 权限Ids
	 * 返回根节点集合
	 * @since JDK 1.7
	 */
	private void associateList( Long parentId, List<Long> pids){
//		List<Map<String,Object>> result= Lists.newArrayList();
		ManagementPermission permission = null;
		if(parentId!=null){
			if(parentId!=0){
				permission = managementPermissionService.findById(parentId);
				pids.add(permission.getId());
				if (permission.getParentId()!=0){
					associateList(permission.getParentId(),pids);
				}
			}
		}
	}


}
